package org.javaforever.infinity.verb;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.javaforever.infinity.core.Verb;
import org.javaforever.infinity.core.Writeable;
import org.javaforever.infinity.domain.Domain;
import org.javaforever.infinity.domain.Dropdown;
import org.javaforever.infinity.domain.Field;
import org.javaforever.infinity.domain.JavascriptBlock;
import org.javaforever.infinity.domain.JavascriptMethod;
import org.javaforever.infinity.domain.Method;
import org.javaforever.infinity.domain.Signature;
import org.javaforever.infinity.domain.Statement;
import org.javaforever.infinity.domain.StatementList;
import org.javaforever.infinity.domain.Type;
import org.javaforever.infinity.domain.Var;
import org.javaforever.infinity.easyui.EasyUIPositions;
import org.javaforever.infinity.generator.NamedStatementGenerator;
import org.javaforever.infinity.generator.NamedStatementListGenerator;
import org.javaforever.infinity.limitedverb.CountSearchByFieldsRecords;
import org.javaforever.infinity.limitedverb.NoControllerVerb;
import org.javaforever.infinity.utils.DomainTokenUtil;
import org.javaforever.infinity.utils.InterVarUtil;
import org.javaforever.infinity.utils.StringUtil;
import org.javaforever.infinity.utils.TableStringUtil;
import org.javaforever.infinity.utils.WriteableUtil;

public class SearchByFieldsByPage extends Verb implements EasyUIPositions {
	protected CountSearchByFieldsRecords countSearch = new CountSearchByFieldsRecords();
	
	@Override
	public Method generateDaoImplMethod() throws Exception{
		Method method = new Method();
		method.setStandardName("search"+this.domain.getPlural()+"ByFieldsByPage");	
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,"connection",new Type("Connection","java.sql"),"java.sql"));
		method.addSignature(new Signature(2,this.domain.getLowerFirstDomainName(),this.domain.getType(),this.domain.getPackageToken(),"Param(value=\""+this.domain.getLowerFirstDomainName()+"\")"));
		method.addSignature(new Signature(3,"pagenum",new Type("Long")));
		method.addSignature(new Signature(4,"pagesize",new Type("Long")));	method.setThrowException(true);
		
		List<Writeable> list = new ArrayList<Writeable>();
		list.add(new Statement(100,2,"try {"));
		list.add(new Statement(200,2,"Long start = (pagenum-1)*pagesize;"));
		list.add(new Statement(300,2,"Long limit = pagesize;"));
		list.add(new Statement(400L,2,"String query = \" select "+ DomainTokenUtil.generateTableCommaFields(domain) + " from "+ domain.getDbPrefix() + TableStringUtil.domainNametoTableName(domain)+" where 1=1 \";"));
		
		long serial = 500L;
		Set<Field> fields = this.domain.getFieldsWithoutId();
		for (Field f:fields){
			if (f.getFieldType().equalsIgnoreCase("string")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null && !\"\".equals("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+")){"));
				list.add(new Statement(serial+100,3,"query += \" and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getFieldName())+" like ? \";"));
			}else{
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null ){"));
				list.add(new Statement(serial+100,3,"query += \" and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getFieldName())+" = ? \";"));
			}
			list.add(new Statement(serial+200,2,"}"));
			serial += 300L;
		}
		list.add(new Statement(serial,2,"query += \"limit ? offset ?;\";"));
		list.add(new Statement(serial+100,2,"//System.out.println(\"JerryDebug:query:\"+query);"));
		list.add(new Statement(serial+200,2,""));
		list.add(new Statement(serial+300,2,"Integer serial = 1;"));
		list.add(new Statement(serial+400,2,"PreparedStatement ps = connection.prepareStatement(query);"));
		list.add(new Statement(serial+500,2,""));
		
		serial += 600L;

		for (Field f:fields){
			if (f.getFieldType().equalsIgnoreCase("string")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null && !\"\".equals("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+")){"));
				list.add(new Statement(serial+100,3,"ps.setString(serial++,\"%\"+"+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"+\"%\");"));
			}else{
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null ){"));
				list.add(new Statement(serial+100,3,"ps.set"+StringUtil.capFirst(f.getPrimaryType().getTypeName())+"(serial++,"+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+");"));
			}
			list.add(new Statement(serial+200,2,"}"));
			serial += 300L;
		}
		list.add(new Statement(serial,2,"ps.setLong(serial++, limit);"));
		list.add(new Statement(serial+100,2,"ps.setLong(serial++,start);"));

		list.add(new Statement(serial+200,2,""));
		list.add(new Statement(serial+300,2,"ResultSet result = ps.executeQuery();"));
		list.add(new Statement(serial+400,2,"ArrayList<"+this.domain.getStandardName()+"> list = new ArrayList<"+this.domain.getStandardName()+">();"));
		list.add(new Statement(serial+500,2,"while(result.next()) {"));
		list.add(new Statement(serial+600,3,"//Build the list object."));
		list.add(new Statement(serial+700,3,this.domain.getStandardName()+" " + this.domain.getLowerFirstDomainName()+"2 = new "+this.domain.getStandardName()+"();"));

		serial += 800;
		Set<Field> fields2 = this.domain.getFields();
		for (Field f:fields2){
			list.add(new Statement(serial,3,StringUtil.lowerFirst(domain.getStandardName())+"2.set"+StringUtil.capFirst(f.getFieldName())+"("+InterVarUtil.DB.result.getVarName()+"."+Type.getPrimeTypeGetterName(f.getFieldType())+"(\""+f.getFieldTableColumName()+"\"));"));
			serial += 100L;
		}
		list.add(new Statement(serial,3,"//Build the object list."));
		list.add(new Statement(serial+100,3,"list.add("+this.domain.getLowerFirstDomainName()+"2);"));
		list.add(new Statement(serial+200,2,"}"));
		list.add(new Statement(serial+300,2,"return list;"));
		list.add(new Statement(serial+400,2,"} catch (Exception e){"));
		list.add(new Statement(serial+500,3,"e.printStackTrace();"));
		list.add(new Statement(serial+600,3,"return null;"));
		list.add(new Statement(serial+700,2,"}"));
				
		method.setMethodStatementList(WriteableUtil.merge(list));
		return method;
	}

	@Override
	public String generateDaoImplMethodString() throws Exception{
		Method m = this.generateDaoImplMethod();
		String s = m.generateMethodString();
		return s;
	}

	@Override
	public Method generateDaoMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,InterVarUtil.DB.connection.getVarName(),InterVarUtil.DB.connection.getVarType()));
		method.addSignature(new Signature(2,this.domain.getLowerFirstDomainName(),this.domain.getType(),this.domain.getPackageToken(),"Param(value=\""+this.domain.getLowerFirstDomainName()+"\")"));
		method.addSignature(new Signature(3,"pagenum",new Type("Long")));
		method.addSignature(new Signature(4,"pagesize",new Type("Long")));
		method.setThrowException(true);
		
		return method;
	}

	@Override
	public String generateDaoMethodDefinitionString()  throws Exception{
		return generateDaoMethodDefinition().generateMethodDefinition();
	}

	@Override
	public String generateDaoImplMethodStringWithSerial()  throws Exception{
		Method m = this.generateDaoImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}

	@Override
	public Method generateServiceMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.addSignature(new Signature(2,"pagenum",new Type("Long")));
		method.addSignature(new Signature(3,"pagesize",new Type("Long")));
		method.setThrowException(true);
		
		return method;
	}

	@Override
	public String generateServiceMethodDefinitionString()  throws Exception{
		return generateServiceMethodDefinition().generateMethodDefinition();
	}

	@Override
	public Method generateControllerMethod()  throws Exception{
		return null;
	}

	@Override
	public String generateControllerMethodString()  throws Exception{
		return null;
	}

	@Override
	public Method generateServiceImplMethod()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.addSignature(new Signature(2,"pagenum",new Type("Long")));
		method.addSignature(new Signature(3,"pagesize",new Type("Long")));
		method.setThrowException(true);
		
		//Service method
		Method daomethod = this.generateDaoMethodDefinition();
				
		List<Writeable> list = new ArrayList<Writeable>();
		list.add(NamedStatementListGenerator.generateServiceImplReturnBoolean(1000L, 2, InterVarUtil.DB.connection, InterVarUtil.DB.dbconf, InterVarUtil.DB.dao, daomethod));
		method.setMethodStatementList(WriteableUtil.merge(list));
		return method;
	}

	@Override
	public String generateServiceImplMethodString()  throws Exception{
		return generateServiceImplMethod().generateMethodString();
	}

	@Override
	public String generateServiceImplMethodStringWithSerial()  throws Exception{
		Method m = this.generateServiceImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}
	
	public SearchByFieldsByPage(){
		super();
		this.setLabel("按字段搜索");
	}
	
	public SearchByFieldsByPage(Domain domain){
		super();
		this.domain = domain;
		this.setVerbName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		this.setLabel("按字段搜索");
	}

	@Override
	public String generateControllerMethodStringWithSerial()  throws Exception{
		return null;
	}

	@Override
	public Method generateFacadeMethod()  throws Exception{
		Method method = new Method();
		method.setStandardName("processRequest");
		method.setReturnType(new Type("void"));
		method.setThrowException(true);
		List<String> list = new ArrayList<String>();
		list.add("ServletException");
		list.add("IOException");
		method.setIsprotected(true);
		method.setOtherExceptions(list);
		method.addSignature(new Signature(1,"request",new Type("HttpServletRequest","javax.servlet.http")));
		method.addSignature(new Signature(2,"response",new Type("HttpServletResponse","javax.servlet.http")));
		method.addAdditionalImport("java.io.IOException");
		method.addAdditionalImport("java.io.PrintWriter");
		method.addAdditionalImport("javax.servlet.ServletException");
		method.addAdditionalImport("javax.servlet.http.HttpServlet");
		method.addAdditionalImport("javax.servlet.http.HttpServletRequest");
		method.addAdditionalImport("javax.servlet.http.HttpServletResponse");
		method.addAdditionalImport("java.util.Map");
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport("java.util.TreeMap");
		method.addAdditionalImport("net.sf.json.JSONObject");
		method.addAdditionalImport(this.domain.getPackageToken()+".utils.StringUtil");
		method.addAdditionalImport(this.domain.getPackageToken()+".utils.BooleanUtil");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addAdditionalImport(this.domain.getPackageToken()+".service."+this.domain.getStandardName()+"Service");
		method.addAdditionalImport(this.domain.getPackageToken()+".serviceimpl."+this.domain.getStandardName()+"ServiceImpl");
		
		List<Writeable> wlist = new ArrayList<Writeable>();
		Var service = new Var("service", new Type(this.domain.getStandardName()+"Service",this.domain.getPackageToken()));
		Var resultMap = new Var("result", new Type("TreeMap<String,Object>","java.util"));
		NoControllerVerb countSearchFields = new CountSearchByFieldsRecords(this.domain);
		
		wlist.add(NamedStatementGenerator.getFacadeSetContentType(1000L, 2, InterVarUtil.Servlet.response, InterVarUtil.SimpleJEE.UTF8.getVarName()));
		wlist.add(NamedStatementGenerator.getControllerPrintWriterOut(2000L, 2, InterVarUtil.Servlet.response, InterVarUtil.Servlet.out));
		wlist.add(NamedStatementGenerator.getJsonResultMap(3000L, 2, resultMap));
		wlist.add(NamedStatementGenerator.getTryHead(4000L, 2));
		wlist.add(new Statement(5000L,3,this.domain.generateTypeVarString() + " = new " + this.domain.getStandardName()+"();"));
		
		long serial = 6000L;
		for (Field f: this.domain.getFieldsWithoutId()){
			wlist.add(NamedStatementGenerator.getFacadeGetParameterByFieldClassTypeSetNull(serial,3,f.getLowerFirstFieldName(),f.getFieldType()));
			serial +=  1000L;
		}
		wlist.add(new Statement(serial,3,"Long pagenum = StringUtil.isBlank(request.getParameter(\"page\"))?1: Long.parseLong(request.getParameter(\"page\"));"));
		wlist.add(new Statement(serial+1000L,3,"Long pagesize = StringUtil.isBlank(request.getParameter(\"rows\"))?10: Long.parseLong(request.getParameter(\"rows\"));"));
		wlist.add(new Statement(serial+2000L,3,"Boolean lastFlagBool = StringUtil.isBlank(request.getParameter(\"last\"))?false: BooleanUtil.parseBoolean(request.getParameter(\"last\"));"));
		wlist.add(new Statement(serial+3000L,3,""));
		serial = serial + 4000L;
		for (Field f: this.domain.getFieldsWithoutId()){
			wlist.add(NamedStatementGenerator.getSetFieldValueByDomainAliasByFieldClassType(serial,3,this.domain,f.getLowerFirstFieldName()));
			serial +=  1000L;
		}
		wlist.add(NamedStatementGenerator.getPrepareService(serial,3, service));		
		wlist.add(new Statement(serial+1000,3, "Long recordCount = "+service.getVarName()+"."+countSearchFields.generateServiceMethodDefinition().getStandardCallString()+";"));
		wlist.add(new Statement(serial+2000,3, "Long pageCount = (long)Math.ceil((double)recordCount/pagesize);"));
		wlist.add(new Statement(serial+3000,3, "if (pageCount <= 1) pageCount = 1L;"));
		wlist.add(new Statement(serial+4000,3, "if (pagenum==null || pagenum <= 1) pagenum = 1L;"));
		wlist.add(new Statement(serial+5000,3, "if (pagenum >= pageCount) pagenum = pageCount;"));
		wlist.add(new Statement(serial+6000,3, "if (lastFlagBool) pagenum = pageCount;"));
		wlist.add(new Statement(serial+7000,3, "List<"+this.domain.getStandardName()+"> list = "+service.getVarName() + "." + generateServiceMethodDefinition().generateStandardServiceImplCallString() + ";"));
		wlist.add(NamedStatementListGenerator.getPutJsonResultMapWithSuccessAndDomainListPaging(serial+8000L, 3, resultMap,new Var("list",new Type("List<"+this.domain.getStandardName()+">")),new Var("pagesize",new Type("Long")),new Var("pagenum",new Type("Long")),new Var("pageCount",new Type("Long"))));
		wlist.add(NamedStatementGenerator.getEncodeMapToJsonResultMap(serial+9000L, 3, resultMap,InterVarUtil.Servlet.out));
		wlist.add(NamedStatementListGenerator.generateCatchExceptionPrintStackPrintJsonMapFinallyCloseOutFooter(serial+10000L, 3, InterVarUtil.Servlet.response,resultMap, InterVarUtil.Servlet.out));
		method.setMethodStatementList(WriteableUtil.merge(wlist));
		
		return method;
	}

	@Override
	public String generateFacadeMethodString()  throws Exception{
		Method m = this.generateFacadeMethod();
		return m.generateMethodString();
	}

	@Override
	public String generateFacadeMethodStringWithSerial()  throws Exception{
		Method m = this.generateFacadeMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}

	@Override
	public JavascriptBlock generateEasyUIJSButtonBlock() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String generateEasyUIJSButtonBlockString() throws Exception {
		return generateEasyUIJSButtonBlock().generateBlockContentString();
	}

	@Override
	public String generateEasyUIJSButtonBlockStringWithSerial() throws Exception {
		return generateEasyUIJSButtonBlock().generateBlockContentStringWithSerial();
	}

	@Override
	public JavascriptMethod generateEasyUIJSActionMethod() throws Exception {
		Domain domain = this.domain;
		JavascriptMethod method = new JavascriptMethod();
		method.setSerial(200);
		method.setStandardName("search"+domain.getPlural()+"ByFieldsByPage");
				
		StatementList sl = new StatementList();
		sl.add(new Statement(1000,1, "params = {"));
		long serial = 2000;
		for (Field f: domain.getFieldsWithoutId()){
			if (f instanceof Dropdown)
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":$(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").combobox(\"getValue\"),"));
			else if (!f.getFieldType().equalsIgnoreCase("boolean"))
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":$(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").val(),"));
			else 
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":parseBoolean($(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").val()),"));
			serial+=1000;
		}	
		sl.add(new Statement(serial,1, "};"));
		sl.add(new Statement(serial+1000,1, "$(\"#dg\").datagrid({queryParams:params});"));
		
		method.setMethodStatementList(sl);
		return method;	
	}

	@Override
	public String generateEasyUIJSActionString() throws Exception {
		return generateEasyUIJSActionMethod().generateMethodString();
	}

	@Override
	public String generateEasyUIJSActionStringWithSerial() throws Exception {
		return generateEasyUIJSActionMethod().generateMethodString();
	}

}
